package binary

import (
	"encoding/binary"
	"encoding/hex"
	"regexp"
	"strconv"
	"strings"
)

type Tag map[string]string

func (t Tag) Has(key string) bool {
	_, ok := t[key]
	return ok
}

func (t Tag) Endian() binary.ByteOrder {
	_, ok := t["little-endian"]
	if ok {
		return binary.BigEndian
	} else {
		return binary.LittleEndian
	}
}

func (t Tag) GetBytes(key string) []byte {
	if h, ok := t[key]; ok {
		return hexOrBytesArrToBytes(h)
	}
	return nil
}

func hexOrBytesArrToBytes(str string) []byte {
	if strings.HasPrefix(str, "0x") {
		if bts, err := hex.DecodeString(strings.TrimPrefix(str, "0x")); err == nil {
			return bts
		}
	} else {
		numbers := strings.Split(str, " ")
		var res = make([]byte, 0)
		for index := 0; index < len(numbers); index++ {
			if num, err := strconv.ParseUint(numbers[index], 0, 8); err == nil {
				res = append(res, byte(num))
			} else {
				return nil
			}
		}
		return res
	}
	return nil
}

func (t Tag) GetFixedBytes() []byte {
	for k, v := range t {
		if v == "" {
			if bts := hexOrBytesArrToBytes(k); bts != nil {
				return bts
			}
		}
	}
	return nil
}

func (t Tag) GetAddrBytes(addrBytes []byte) []byte {
	if _, ok := t["address"]; ok {
		return addrBytes
	} else {
		for k, _ := range t {
			if strings.HasPrefix(k, "address") {
				var numbers = regexp.MustCompile("\\d+").FindAllString(k, -1)
				if len(numbers) > 0 {
					var parts = make([]byte, len(numbers))
					for k, numS := range numbers {
						num, _ := strconv.Atoi(numS)
						parts[k] = byte(num)
					}
					return parts
				}
			}
		}
	}
	return nil
}

func (t Tag) GetInt(key string) int {
	if v, ok := t[key]; ok {
		num, _ := strconv.Atoi(v)
		return num
	}
	return 0
}

func ParseTag(tag string) Tag {
	var tags = strings.Split(tag, ",")
	var result = make(Tag)
	for _, t := range tags {
		ts := strings.Split(t, ":")
		if len(ts) > 1 {
			result[ts[0]] = ts[1]
		} else {
			result[ts[0]] = ""
		}
	}
	return result
}
